home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / cenvid9.zip / CMMEDIT.CMM < prev    next >
Text File  |  1994-03-04  |  16KB  |  409 lines

  1. /**************************************************************************
  2.  *** CmmEdit - A simple text editor.  This is the tutorial program from ***
  3.  *** ver.1     chapter 3 of the CEnvi manual.                           ***
  4.  **************************************************************************/
  5.  
  6. main(ArgCount,ArgList)
  7. {
  8.    FileName = GetFileName(ArgCount,ArgList);
  9.    ReadFile(FileName);
  10.    if ( Edit() )  // Edit returns TRUE if changes made to file
  11.       WriteFile(FileName);
  12. }
  13.  
  14.  
  15. GetFileName(argc,argv)
  16.    // return a file name from the program input arguments, or prompt user for the
  17.    // file name if none was supplied at the command line.  exit() program if no
  18.    // file name is gotten.
  19. {
  20.    // If at least one argument was supplied to main() in addition to the source
  21.    // file name (which is always supplied), then that argument is the  file name.
  22.    if ( 1 < argc )
  23.       return(argv[1]);
  24.  
  25.    // File name wasn't supplied on the command line, and so prompt for name.
  26.    printf("Enter file name to edit: ");
  27.    filespec = gets();
  28.    if ( filespec == NULL || filespec[0] == 0 )  // no name was entered so quit
  29.       exit(EXIT_FAILURE);
  30.    return(filespec);
  31. }
  32.  
  33. Text[0] = "";  // Text is an array of s text strings; one for each file line
  34.  
  35. ReadFile(FileSpec)   // read FileSpec file into global data.  exit() if error.
  36. {
  37.    // Open the file, in text mode, for reading into Text.
  38.    fp = fopen(FileSpec,"rt");
  39.    if ( fp == NULL ) {
  40.       // The file doesn't exist, and so ask user if they want to quit.  If they
  41.       // don't want to create file then simply exit this program.  If they do
  42.       // want to create file then we're done, as Text is already initialized.
  43.       printf("File \"%s\" does not exist.  Create file?  Y/N ",FileSpec);
  44.       do {
  45.          key = toupper(getch()); // make uppercase to compare to Y and N
  46.          if ( key == 'N' )
  47.             exit(EXIT_FAILURE);
  48.       } while( key != 'Y' );     // wasn't Y or N, and so try again
  49.    } else {
  50.       // File opened.  Read each line of file into the next element of Text.
  51.       for ( LineCount = 0; NULL != (line = fgets(fp)); LineCount++ ) {
  52.          // line set to new string for next line in the text file.  Set the next
  53.          // line of Text to this line.
  54.          Text[LineCount] = line;
  55.       }
  56.       fclose(fp); // Should always close a file that has been opened.
  57.    }
  58. }
  59.  
  60. WriteFile(FileSpec)  // write global data to back to FileSpec.  exit() if error.
  61. {
  62.    // Open FileSpec for writing in text mode.  If the file already exists then
  63.    // truncate the file.  If file doesn't exist then create it.
  64.    fp = fopen(FileSpec,"wt");
  65.    if ( fp == NULL ) {
  66.       printf("\aUnable to open \"%s\" for writing.\a\n");
  67.       exit(EXIT_FAILURE);
  68.    }
  69.  
  70.    // write every line of Text into fp
  71.    for ( i = 0; i <= GetArraySpan(Text); i++ )
  72.       fputs( Text[i], fp );
  73.  
  74.    // close fp
  75.    fclose(fp);
  76. }
  77.  
  78.  
  79. // define movement keys - Give values over 0x100 to distinguish from text
  80. #define  MIN_CUR_MOVE   0x101
  81. #define  UP             0x101
  82. #define  DOWN           0x102
  83. #define  LEFT           0x103
  84. #define  RIGHT          0x104
  85. #define  PG_UP          0x105
  86. #define  PG_DN          0x106
  87. #define  HOME           0x107
  88. #define  END            0x108
  89. #define  BK_TAB         0x109
  90. #define  DELETE         0x110
  91.  
  92. GetKeyChar()   // return key from keyboard, ascii for above #defined
  93. {
  94.    if defined(_DOS_)  ||  defined(_OS2_) {
  95.       // DOS and OS/2 return 0 on first getch for extended keys
  96.       KeyCode = getch();
  97.       if ( KeyCode == 0 ) {
  98.          // set value for extended key; these value found using KeyCode.cmd
  99.          switch( getch() ) {
  100.             case 0x48:     KeyCode = UP;        break;
  101.             case 0x50:     KeyCode = DOWN;      break;
  102.             case 0x4B:     KeyCode = LEFT;      break;
  103.             case 0x4D:     KeyCode = RIGHT;     break;
  104.             case 0x49:     KeyCode = PG_UP;     break;
  105.             case 0x51:     KeyCode = PG_DN;     break;
  106.             case 0x47:     KeyCode = HOME;      break;
  107.             case 0x4F:     KeyCode = END;       break;
  108.             case 0x0F;     KeyCode = BK_TAB;    break;
  109.             case 0x53;     KeyCode = DELETE;    break;
  110.             default: break;   // return 0, which will do nothing
  111.          }
  112.       }
  113.    } else {
  114.       // Windows version
  115.       KeyCode = getch();
  116.       if ( 0x100 < KeyCode ) {
  117.          switch ( KeyCode ) {
  118.             // special values in the following table come from KeyCode.cmm
  119.             case 0x126:    KeyCode = UP;        break;
  120.             case 0x128:    KeyCode = DOWN;      break;
  121.             case 0x125:    KeyCode = LEFT;      break;
  122.             case 0x127:    KeyCode = RIGHT;     break;
  123.             case 0x121:    KeyCode = PG_UP;     break;
  124.             case 0x122:    KeyCode = PG_DN;     break;
  125.             case 0x124:    KeyCode = HOME;      break;
  126.             case 0x123:    KeyCode = END;       break;
  127.             case 0x109;    KeyCode = BK_TAB;    break;
  128.             case 0x12E;    KeyCode = DELETE;    break;
  129.             default:       KeyCode = 0;         break;
  130.          }
  131.       }
  132.    }
  133.    return(KeyCode);
  134. }
  135.  
  136.  
  137. Edit()   // Edit file.  This is were the hard work happens.  exit() if error.
  138. {        // Return FALSE if no editing was done, else return TRUE.
  139.    LineCount = 1 + GetArraySpan(Text); // how many lines in file
  140.  
  141.    // Initialize screen: get its dimensions, and cursor location.
  142.    ScreenClear();
  143.    ScreenDimension = ScreenSize();
  144.    CursorCol = CursorRow = 0; // initialize cursor position
  145.  
  146.    // Starting at row 0, draw all lines on screen. Initialize Start as structure
  147.    // for upper-left visible portion of file. Then draw the file.
  148.    Start.Row = Start.Col = 0;
  149.    DrawVisibleTextLines( Start, ScreenDimension, LineCount );
  150.    DrawnStart = Start;  // remember which lines were drawn
  151.    CursorStatus(CursorRow,CursorCol,Start,ScreenDimension);
  152.  
  153.    // FileWasEdited is boolean to say if changes made
  154.    FileWasEdited = FALSE;
  155.  
  156.    // Stay here getting all keyboard input until escape is pressed
  157.    #define  ESCAPE_KEY  '\033'
  158.    while ( (key = GetKeyChar()) != ESCAPE_KEY ) {
  159.  
  160.       // special keyboard codes are returned if getch() first
  161.       switch( key ) {
  162.          case UP:    CursorRow--;   break;
  163.          case DOWN:  CursorRow++;   break;
  164.          case LEFT:  CursorCol--;   break;
  165.          case RIGHT: CursorCol++;   break;
  166.          case HOME:  CursorCol = 0; break;
  167.          case END:
  168.             // go to end of visible line, but not including newline
  169.             CursorCol = strlen(Text[CursorRow]);
  170.             if ( 0 < CursorCol  &&  Text[CursorRow][CursorCol-1] == '\n' )
  171.                CursorCol--;
  172.             break;
  173.          case PG_UP:
  174.             CursorRow -= (ScreenDimension.row - 1);
  175.             Start.Row -= (ScreenDimension.row - 1);
  176.             break;
  177.          case PG_DN:
  178.             CursorRow += (ScreenDimension.row - 1);
  179.             Start.Row += (ScreenDimension.row - 1);
  180.             break;
  181.  
  182.          #define  TABSIZE  8
  183.          case '\t':
  184.             CursorCol += TABSIZE;
  185.             CursorCol -= CursorCol % TABSIZE;
  186.             break;
  187.          case BK_TAB:
  188.             CursorCol -= TABSIZE;
  189.             CursorCol -= CursorCol % TABSIZE;
  190.             break;
  191.  
  192.          #define BACKSPACE '\010'
  193.          case BACKSPACE:
  194.             // Back space is just like deleting from one column to the left,
  195.             // and so check that we're not on the first column and then move
  196.             // left a column and let control fall to DELETE
  197.             if ( --CursorCol < 0 )    {
  198.                // backspace from beginning of line; move to end of previous line
  199.                if ( CursorRow == 0 ) {
  200.                   // cannot backup to earlier row, so do nothing
  201.                   CursorCol = 0;
  202.                   break;
  203.                }
  204.                CursorCol = strlen(Text[--CursorRow]) - 1;
  205.             }
  206.          case DELETE:
  207.             if ( DeleteCharacterAtCursor(CursorRow,CursorCol,LineCount) ) {
  208.                FileWasEdited = TRUE